/**
 * 还款和提前还款专用的逻辑处理
 */
package com.p2p.front.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import com.p2p.base.constents.InnerAccountConsts;
import com.p2p.base.exception.BizException;
import com.p2p.base.model.Money;
import com.p2p.base.util.DateUtil;
import com.p2p.front.dal.model.LoanInfo;
import com.p2p.front.dal.model.LoanRepay;
import com.p2p.front.dal.model.Tender;
import com.p2p.front.dal.model.TenderReturn;
import com.p2p.front.enums.LoanRepayStatus;
import com.p2p.front.enums.TenderReturnStatus;
import com.p2p.front.enums.TenderStatus;
import com.p2p.front.result.LoanRepayResult;
import com.p2p.front.result.LoanRepayResult.ResultCodeEnum;
import com.p2p.front.service.LoanInfoService;
import com.p2p.front.service.LoanRepayBizService;
import com.p2p.front.service.LoanRepayService;
import com.p2p.front.service.TenderReturnService;
import com.p2p.front.service.TenderService;
import com.p2p.front.service.TransferService;
import com.p2p.front.service.model.BizReturnAdvanceModel;
import com.p2p.front.util.LoanRepayUtil;
import com.p2p.trans.client.enums.SubTransCodeEnum;
import com.p2p.trans.client.enums.TransCodeEnum;
import com.p2p.trans.client.facade.AccountQueryFacade;
import com.p2p.trans.client.facade.AccountTransFacade;
import com.p2p.trans.client.model.TransInfo;
import com.p2p.trans.client.result.AccountTransResult;

/**
 * @author ruiqi
 *
 */
@Service("loanRepayBizService")
public class LoanRepayBizServiceImpl implements LoanRepayBizService {

	protected final Logger logger = LoggerFactory.getLogger(LoanRepayServiceImpl.class);
	
	@Resource
	private LoanRepayService loanRepayService;
	
	@Resource
	private LoanInfoService loanInfoService;
	
	@Resource
	protected TenderReturnService tenderReturnService;
	
	@Resource
	protected TenderService tenderService;
	
	@Resource
	protected AccountTransFacade remoteAccountTransFacade;
	
	@Resource
	protected AccountQueryFacade remoteAccountQueryFacade;
	
	@Resource
	private PlatformTransactionManager transactionManager;
	
	@Resource
	private TransferService transferService;
	
	
	public LoanRepayResult doRepayForAdvance(Long loanId, Money fine,boolean needRepay){
		LoanRepayResult mainResult = new LoanRepayResult();
		//判断是否需要扣除还款金额，比如普通标
		LoanRepayResult loanRepayAdvanceResult = loanRepayService.doTransRepayForAdvance(loanId,fine,needRepay);
		if(!loanRepayAdvanceResult.isSuccess()){
			return loanRepayAdvanceResult;
		}
		LoanInfo loanInfo = loanInfoService.getLoanInfoById(loanId);
		
		List<LoanRepay> loanRepayList = loanRepayService.queryByLoanIdAndStatus(loanId, 11);
		
		//取出所有未还还款,依次调用还款接口
		for(LoanRepay loanRepay:loanRepayList){
			LoanRepayResult loanRepayResult = loanRepayService.doRepay2(loanRepay.getRid(), true, loanInfo);
			if(!loanRepayResult.isSuccess()){
				return loanRepayResult;
			}
		}
		
		mainResult.setSuccess(true);
		return mainResult;
		
	}
	public LoanRepayResult doRepayForNomalCheck(LoanRepay loanRepay){
		LoanRepayResult mainResult = new LoanRepayResult();
		
		if(loanRepay==null){
			mainResult.setResultCode(LoanRepayResult.ResultCodeEnum.LoanRepay_parameters_error.name());
			return mainResult;
		}
		Date now = new Date();
		if(DateUtil.getDayBetweenTwoDate(now.getTime(), loanRepay.getStartTime().getTime())<0){
			mainResult.setResultCode(LoanRepayResult.ResultCodeEnum.LoanRepay_date_not_allow.name());
			return mainResult;
		}
		if(loanRepay.getStatus()!=11){
			mainResult.setResultCode(LoanRepayResult.ResultCodeEnum.LoanRepay_status_error.name());
			return mainResult;
		}
		mainResult.setSuccess(true);
		return mainResult;
		
	}
	public LoanRepayResult doRepayForNomal(Long rid, Money fine,boolean needRepay){
		LoanRepayResult mainResult = new LoanRepayResult();
		LoanRepay loanRepay = loanRepayService.getByRid(rid);
		if(loanRepay==null){
			mainResult.setResultCode(LoanRepayResult.ResultCodeEnum.LoanRepay_parameters_error.name());
			return mainResult;
		}
		Date now = new Date();
		if(DateUtil.getDayBetweenTwoDate(now.getTime(), loanRepay.getStartTime().getTime())<0){
			mainResult.setResultCode(LoanRepayResult.ResultCodeEnum.LoanRepay_date_not_allow.name());
			return mainResult;
		}
		LoanInfo loanInfo = loanInfoService.getLoanInfoById(loanRepay.getLid());
		//判断是否需要扣除还款金额，比如普通标
		if(loanInfo.getIsFlow()==0&&needRepay){
			boolean loanRepayAdvanceResult = loanRepayService.doTransForLoanRepay(loanRepay, loanInfo);
			if(!loanRepayAdvanceResult){
				mainResult.setResultCode(LoanRepayResult.ResultCodeEnum.LoanRepay_balance_not_enough.name());
				return mainResult;
			}
		}
		
		//取消债权转让
		transferService.cancelTransferByLid(loanInfo.getLid());
		
		LoanRepayResult loanRepayResult = loanRepayService.doRepay2(loanRepay.getRid(), false, loanInfo);
		if(!loanRepayResult.isSuccess()){
			return loanRepayResult;
		}
		
		mainResult.setSuccess(true);
		return mainResult;
		
	}
	
	/*public LoanRepayResult doRepayForNomal2(Long rid, Money fine,boolean needRepay){
		LoanRepayResult mainResult = new LoanRepayResult();
		LoanRepay loanRepay = loanRepayService.getByRid(rid);
		if(loanRepay==null){
			mainResult.setResultCode(LoanRepayResult.ResultCodeEnum.LoanRepay_parameters_error.name());
			return mainResult;
		}
		Date now = new Date();
		if(DateUtil.getDayBetweenTwoDate(now.getTime(), loanRepay.getStartTime().getTime())<0){
			mainResult.setResultCode(LoanRepayResult.ResultCodeEnum.LoanRepay_date_not_allow.name());
			return mainResult;
		}
		LoanInfo loanInfo = loanInfoService.getLoanInfoById(loanRepay.getLid());
		//判断是否需要扣除还款金额，比如普通标
		if(loanInfo.getIsFlow()==0&&needRepay){
			boolean loanRepayAdvanceResult = loanRepayService.doTransForLoanRepay(loanRepay, loanInfo);
			if(!loanRepayAdvanceResult){
				mainResult.setResultCode(LoanRepayResult.ResultCodeEnum.LoanRepay_balance_not_enough.name());
				return mainResult;
			}
		}
		
		//List<TenderReturn> tenderReturnList = queryTenderReturn(loanRepay);
		LoanRepayResult loanRepayResult = loanRepayService.doRepay2(loanRepay.getRid(), false, loanInfo);
		if(!loanRepayResult.isSuccess()){
			return loanRepayResult;
		}
		
		mainResult.setSuccess(true);
		return mainResult;
		
	}*/
	
	private LoanRepayResult checkStatus(BizReturnAdvanceModel bizReturnAdvanceModel){
		LoanRepayResult loanRepayResult  = new LoanRepayResult();
		List<LoanRepay> repayList = bizReturnAdvanceModel.getLoanRepayList();
		
		
		if(CollectionUtils.isEmpty(repayList)){
			loanRepayResult.setResultCode(ResultCodeEnum.LoanRepay_status_error.name());
			return loanRepayResult;
		}
		
		LoanRepay earliestloanRepay = repayList.get(0);
		if(LoanRepayUtil.hasInterest(earliestloanRepay)){
			loanRepayResult.setResultCode(ResultCodeEnum.LoanRepay_has_Interest.name());
			return loanRepayResult;
		}
		loanRepayResult.setSuccess(true);
		return loanRepayResult;
	}

	public LoanRepayResult doRepayForAdvance2Check(BizReturnAdvanceModel bizReturnAdvanceModel){
		final LoanRepayResult loanRepayResult = checkStatus(bizReturnAdvanceModel);
		if (!loanRepayResult.isSuccess()) {
			return loanRepayResult;
		}
		loanRepayResult.setSuccess(false);
		if (!bizReturnAdvanceModel.checkPass()) {
			loanRepayResult
					.setResultCode(ResultCodeEnum.LoanRepay_amount_check_error
							.name());
			return loanRepayResult;
		}
		loanRepayResult.setSuccess(true);
		return loanRepayResult;
	}
	
	public LoanRepayResult doRepayForAdvance2(final Long loanId, Money fine,
			boolean needRepay) {

		
		final BizReturnAdvanceModel bizReturnAdvanceModel = getBizReturnAdvanceModel(loanId);

		final LoanRepayResult loanRepayResult = doRepayForAdvance2Check(bizReturnAdvanceModel);
		// 判断是否需要扣除还款金额，比如普通标
		LoanRepayResult loanRepayAdvanceResult = loanRepayService
				.doTransRepayForAdvance(loanId, fine, needRepay);
		if (!loanRepayAdvanceResult.isSuccess()) {
			return loanRepayAdvanceResult;
		}
		TransactionTemplate transactionTemplate = new TransactionTemplate(
				transactionManager);
		transactionTemplate
				.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);

		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus status) {

				try {

					doLoanRepayAdvance(bizReturnAdvanceModel);
					doTenderTeturnAdvance(bizReturnAdvanceModel);
					//取消债权转让
					transferService.cancelTransferByLid(loanId);
					doTenderAdvance(bizReturnAdvanceModel);
				} catch (BizException e) {
					logger.error("do return advance error", e);
					loanRepayResult.setResultCode(e.getCode());
					status.setRollbackOnly();
				} catch (Exception e) {
					logger.error("do return advance error", e);
					loanRepayResult
							.setResultCode(LoanRepayResult.ResultCodeEnum.LoanRepay_system_exception
									.name());
					status.setRollbackOnly();
				}
			}
		});

		if (StringUtils.isNotBlank(loanRepayResult.getResultCode())) {
			return loanRepayResult;
		}

		boolean returnResult = doReturnAccountTrans(bizReturnAdvanceModel);
		if(!returnResult){
			loanRepayResult.setResultCode(LoanRepayResult.ResultCodeEnum.LoanRepay_success_but_account_trans_fail.name());
			return loanRepayResult;
		}
		boolean fineResult = doFineForTender(bizReturnAdvanceModel, fine);
		if(!fineResult){
			loanRepayResult.setResultCode(LoanRepayResult.ResultCodeEnum.LoanRepay_success_but_account_trans_fine_fail.name());
			return loanRepayResult;
		}
		loanRepayResult.setSuccess(true);
		return loanRepayResult;
	}
	public void doLoanRepayAdvance(BizReturnAdvanceModel bizReturnAdvanceModel){
		List<LoanRepay> repayList = bizReturnAdvanceModel.getLoanRepayList();
		for(LoanRepay loanRepay:repayList){
			boolean updateResult = loanRepayService.updateStatusForReturn(loanRepay.getRid(), LoanRepayStatus.REPAYING.getCode(), LoanRepayStatus.REPAY_SUCCEED.getCode());
			if(!updateResult){
				logger.warn("updateStatusForLoanRepayAdvance fall ,loanRepey Id="+loanRepay.getRid() );
			}
		}
		
	}
	private void doTenderTeturnAdvance(BizReturnAdvanceModel bizReturnAdvanceModel){
		List<TenderReturn> returnList = bizReturnAdvanceModel.getTenderReturnList();
		Money zeroAmount = new Money(0,0);
		for(TenderReturn tenderReturn:returnList){
			boolean updateResult = tenderReturnService.updateStatusForReturn(tenderReturn.getId(), TenderReturn.ReturnType.ADVANCE.getCode(), zeroAmount);
			if(!updateResult){
				logger.warn("updateStatusForTenderReturnAdvance fall ,tenderReturn Id="+tenderReturn.getId());
			}
		}
	}
	private void doTenderAdvance(BizReturnAdvanceModel bizReturnAdvanceModel){
		Map<Long,Tender> tendermap = bizReturnAdvanceModel.getTenderMap();
		for(Tender tender:tendermap.values()){
			boolean updateResult = this.tenderService.updateTenderStatus(tender.getTid(), TenderStatus.REPAYED.getCode());
			if(!updateResult){
				logger.warn("updateStatusForTender fall ,tender Id="+tender.getTid());
			}
		}
	}
	public boolean doReturnAccountTrans(BizReturnAdvanceModel bizReturnAdvanceModel){
		tender2MiddleTrans(bizReturnAdvanceModel.getAllReturnPrincipal(),"提前还款打款");
		List<TransInfo> transList = bizReturnAdvanceModel.getTenderReturnTransInfoList();
		AccountTransResult transResult = remoteAccountTransFacade.batchTransfer(transList);
		if(!transResult.isSuccess()){
			logger.error("batchTransfer fall for returnAdvance, transErrorCode = "+transResult.getResultCode()+", loanId="+bizReturnAdvanceModel.getLoanInfo().getLid());
			this.middle2TenderTrans(bizReturnAdvanceModel.getAllReturnPrincipal(),"提前还款打款退回");
		}
		return transResult.isSuccess();
	}
	public boolean doFineForTender(BizReturnAdvanceModel bizReturnAdvanceModel,Money fine){
		if(fine==null||fine.getCent()==0l){
			return true;
		}
		tender2MiddleTrans(fine,"提前还款违约金打款");
		List<TransInfo> transList = bizReturnAdvanceModel.getReturnAdvanceFine(fine);
		AccountTransResult transResult = remoteAccountTransFacade.batchTransfer(transList);
		if(!transResult.isSuccess()){
			logger.error("batchTransfer fall for returnAdvance fine, transErrorCode = "+transResult.getResultCode()+",loanId="+bizReturnAdvanceModel.getLoanInfo().getLid());
			this.middle2TenderTrans(fine,"提前还款违约金打款退回");
		}
		return transResult.isSuccess();
	}
	
	public BizReturnAdvanceModel getBizReturnAdvanceModel(Long loanId) {
		LoanInfo loanInfo  = loanInfoService.getLoanInfoById(loanId);
		List<LoanRepay> repayList = this.loanRepayService
				.queryByLoanIdAndStatus(loanId,
						LoanRepayStatus.REPAYING.getCode());
		// 获取所有剩余的还款
		List<TenderReturn> allReturnList = new ArrayList<TenderReturn>();

		for (LoanRepay loanRepay : repayList) {
			List<TenderReturn> tempList = queryTenderReturnByRepayAndStatus(loanRepay,TenderReturnStatus.RECYCLING.getCode());
			allReturnList.addAll(tempList);
		}
		// 按投标id为key的map，投标信息里有用户的accountNo等信息
		Map<Long, Tender> tenderMap = getTenderRepaying(loanId);
		BizReturnAdvanceModel bizReturnAdvanceModel = new BizReturnAdvanceModel(
				loanInfo,repayList, allReturnList, tenderMap);
		bizReturnAdvanceModel.init();
		return bizReturnAdvanceModel;
	}

	/**
	 * 获取所有还款中的投标，Map格式
	 * @param loanId
	 * @return
	 */
	private Map<Long,Tender> getTenderRepaying(Long loanId){
		Map<Long,Tender> map = new HashMap<Long,Tender>();
		List<Tender> tenderList = tenderService.findByLoanIdAndStatus(loanId, TenderStatus.REAPYING);
		for(Tender tender:tenderList){
			map.put(tender.getTid(), tender);
		}
		return map;
	}
	private List<TenderReturn> queryTenderReturnByRepayAndStatus(LoanRepay loanRepay,Integer status){
		List<TenderReturn> returnList = tenderReturnService.queryByLidAndNoAndStatus(loanRepay.getLid(), loanRepay.getNo(),status);
		return returnList;
	}
	public AccountTransResult tender2MiddleTrans(Money amount,String memo){
		TransInfo transInfo = new TransInfo();
		transInfo.setTransCode(TransCodeEnum.TXCODE_TRANSFER);
		transInfo.setSubTransCode(SubTransCodeEnum.SUB_TRANSFER_RETURN_BATCH);
		transInfo.setTransAccountIn(InnerAccountConsts.innerMiddleAccountNo);
		transInfo.setTransAccountOut(InnerAccountConsts.innerTenderAccountNo);
		transInfo.setTransAmount(amount);
		transInfo.setTransMemo(memo);
		AccountTransResult transResult = remoteAccountTransFacade.transfer(transInfo);
		return transResult;
	}
	
	public AccountTransResult middle2TenderTrans(Money amount,String memo){
		TransInfo transInfo = new TransInfo();
		transInfo.setTransCode(TransCodeEnum.TXCODE_TRANSFER);
		//归集转账仍然用SUB_TRANSFER_TENDER
		transInfo.setSubTransCode(SubTransCodeEnum.SUB_TRANSFER_RETURN_BATCH_BACK);
		transInfo.setTransAccountIn(InnerAccountConsts.innerTenderAccountNo);
		transInfo.setTransAccountOut(InnerAccountConsts.innerMiddleAccountNo);
		transInfo.setTransAmount(amount);
		transInfo.setTransMemo(memo);
		AccountTransResult transResult = remoteAccountTransFacade.transfer(transInfo);
		return transResult;
	}
}
